/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Converter.h"
#include <stdio.h>
#include <stdlib.h>
#include <wctype.h>
#include <wchar.h>
#include <math.h>
#include <string.h>

#ifdef SAMSUNG_VERSION
#include <samsung/swprintf.h>

#define sprintf(str, format, ...) snprintf(str, 0xFFFF, format, __VA_ARGS__)
#endif

#ifdef WIN_VERSION
#include <win32/win32.h>
#endif



namespace liba
{
namespace converter
{

const char CharTraits<char>::ANGULAR_BRACKET_LEFT = '<';
const char CharTraits<char>::ANGULAR_BRACKET_RIGHT = '>';
const char CharTraits<char>::SLASH = '/';
const char CharTraits<char>::BACKSLASH = '\\';
const char CharTraits<char>::PALKA = '|';
const char CharTraits<char>::EQUAL = '=';
const char CharTraits<char>::QUOTE = '"';
const char CharTraits<char>::APOS = '\'';
const char CharTraits<char>::QUESTION = '?';
const char CharTraits<char>::EXCLAMATION = '!';
const char CharTraits<char>::SEMICOLON = ';';
const char CharTraits<char>::MINUS = '-';
const char CharTraits<char>::PLUS = '+';
const char CharTraits<char>::ZERO = '0';
const char CharTraits<char>::DOT = '.';
const char CharTraits<char>::SPACE = ' ';
const char CharTraits<char>::TAB = '\t';
const char CharTraits<char>::COLON = ',';
const char CharTraits<char>::ENDL = '\n';

int CharTraits<char>::convert_digit( char v )
{
	return v - '0';
}
bool CharTraits<char>::is_space( char v )
{
	return isspace( v );
}
bool CharTraits<char>::is_digit( char v )
{
	return isdigit( v );
}

const wchar_t CharTraits<wchar_t>::ANGULAR_BRACKET_LEFT = L'<';
const wchar_t CharTraits<wchar_t>::ANGULAR_BRACKET_RIGHT = L'>';
const wchar_t CharTraits<wchar_t>::SLASH = L'/';
const wchar_t CharTraits<wchar_t>::BACKSLASH = L'\\';
const wchar_t CharTraits<wchar_t>::PALKA = L'|';
const wchar_t CharTraits<wchar_t>::EQUAL = L'=';
const wchar_t CharTraits<wchar_t>::QUOTE = L'"';
const wchar_t CharTraits<wchar_t>::APOS = L'\'';
const wchar_t CharTraits<wchar_t>::QUESTION = L'?';
const wchar_t CharTraits<wchar_t>::EXCLAMATION = L'!';
const wchar_t CharTraits<wchar_t>::SEMICOLON = L';';
const wchar_t CharTraits<wchar_t>::MINUS = L'-';
const wchar_t CharTraits<wchar_t>::PLUS = L'+';
const wchar_t CharTraits<wchar_t>::ZERO = L'0';
const wchar_t CharTraits<wchar_t>::DOT = L'.';
const wchar_t CharTraits<wchar_t>::SPACE = L' ';
const wchar_t CharTraits<wchar_t>::TAB = L'\t';
const wchar_t CharTraits<wchar_t>::COLON = L',';
const wchar_t CharTraits<wchar_t>::ENDL = L'\n';

int CharTraits<wchar_t>::convert_digit( wchar_t v )
{
	return v - L'0';
}
bool CharTraits<wchar_t>::is_space( wchar_t v )
{
	return iswspace( v );
}
bool CharTraits<wchar_t>::is_digit( wchar_t v )
{
	return iswdigit( v );
}

EnumPair<char,bool> InternalBoolNames[] = 
{
	MakeEnumPair("false",false),
	MakeEnumPair("true",true),
	MakeEnumPair("0",false),
	MakeEnumPair("1",true),
	MakeEnumPair("False",false),
	MakeEnumPair("True",true),
	MakeEnumPair("FALSE",false),
	MakeEnumPair("TRUE",true),
	0
};

EnumPair<wchar_t,bool> InternalBoolWNames[] = 
{
	MakeEnumPair(L"false",false),
	MakeEnumPair(L"true",true),
	MakeEnumPair(L"0",false),
	MakeEnumPair(L"1",true),
	MakeEnumPair(L"False",false),
	MakeEnumPair(L"True",true),
	MakeEnumPair(L"FALSE",false),
	MakeEnumPair(L"TRUE",true),
	0
};

template<typename Sym,typename T>
const Sym * any_int_convert( const Sym * ptr, const Sym * end, T * number )
{
    while( ptr != end && CharTraits<Sym>::is_space(*ptr) )
        ++ptr;
	if( ptr == end )
		return 0;
    int c = *ptr++;
    int sign = c;
    if( c == CharTraits<Sym>::MINUS || c == CharTraits<Sym>::PLUS )
	{
		if( ptr == end )
			return 0;
        c = *ptr++;
	}
    T total = 0;
	bool any_digit = false;

    while( CharTraits<Sym>::is_digit( c ) )
	{
		any_digit = true;
        total = 10 * total + CharTraits<Sym>::convert_digit(c);
		if( ptr == end )
			break;
        c = *ptr++;
    }
    if (sign == CharTraits<Sym>::MINUS)
        *number = -total;
    else
        *number = total;
	return any_digit ? ptr : 0;
}

template<typename Sym,typename T>
const Sym * any_unsigned_convert( const Sym * ptr, const Sym * end, T * number )
{
	while( ptr != end && CharTraits<Sym>::is_space(*ptr) )
		++ptr;
	if( ptr == end )
		return 0;
	int c = *ptr++;
	if( c == CharTraits<Sym>::PLUS )
	{
		if( ptr == end )
			return 0;
		c = *ptr++;
	}
	T total = 0;
	bool any_digit = false;

	while( CharTraits<Sym>::is_digit( c ) )
	{
		any_digit = true;
		total = 10 * total + CharTraits<Sym>::convert_digit(c);
		if( ptr == end )
			break;
		c = *ptr++;
	}
	*number = total;
	return any_digit ? ptr : 0;
}


template<typename Sym,typename T>
const Sym * any_float_convert( const Sym * ptr, const Sym * end, T * number )
{
    while( ptr != end && CharTraits<Sym>::is_space(*ptr) )
        ++ptr;
	if( ptr == end )
		return 0;
    int c = *ptr++;
    int sign = c;
    if( c == CharTraits<Sym>::MINUS || c == CharTraits<Sym>::PLUS )
	{
		if( ptr == end )
			return 0;
        c = *ptr++;
	}
    T total = 0;
	bool any_digit = false;

    while( CharTraits<Sym>::is_digit( c ) )
	{
		any_digit = true;
        total = 10 * total + CharTraits<Sym>::convert_digit(c);
		if( ptr == end )
			break;
        c = *ptr++;
    }
	if( c == CharTraits<Sym>::DOT )
	{
		if( ptr != end )
		{
			c = *ptr++;
			T mul = T(0.1);
		    while( CharTraits<Sym>::is_digit( c ) )
			{
				any_digit = true;
				total += mul * CharTraits<Sym>::convert_digit(c);
				mul *= T(0.1);
				if( ptr == end )
					break;
				c = *ptr++;
			}
		}
	}
	if( CharTraits<Sym>::is_e( c ) )
	{
		int exponent = 0;
		ptr = any_int_convert<Sym,int>( ptr, end, &exponent );
		if( !ptr )
			return 0;
		total *= T( pow( 10.0, exponent ) );
	}
    if (sign == CharTraits<Sym>::MINUS)
        *number = -total;
    else
        *number = total;
	return any_digit ? ptr : 0;
}

const char * simple_convert(const char * ptr, const char * end, short * value)
{
	return any_int_convert<char,short>(ptr, end, value);
}
const char * simple_convert(const char * ptr, const char * end, int * value)
{
	return any_int_convert<char,int>(ptr, end, value);
}
const char * simple_convert(const char * ptr, const char * end, unsigned * value)
{
	return any_unsigned_convert<char,unsigned>(ptr, end, value);
}
const char * simple_convert(const char * ptr, const char * end, long * value)
{
	return any_int_convert<char,long>(ptr, end, value);
}
const char * simple_convert(const char * ptr, const char * end, unsigned long * value)
{
	return any_unsigned_convert<char,unsigned long>(ptr, end, value);
}
const char * simple_convert(const char * ptr, const char * end, __int64 * value)
{
	return any_int_convert<char,__int64>(ptr, end, value);
}
const char * simple_convert(const char * ptr, const char * end, float * value)
{
	return any_float_convert(ptr, end, value);
}
const char * simple_convert(const char * ptr, const char * end, double * value)
{
	return any_float_convert(ptr, end, value);
}
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, short * value)
{
	return any_int_convert<wchar_t,short>(ptr, end, value);
}
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, int * value)
{
	return any_int_convert<wchar_t,int>(ptr, end, value);
}
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, unsigned * value)
{
	return any_unsigned_convert(ptr, end, value);
}
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, long * value)
{
	return any_int_convert<wchar_t,long>(ptr, end, value);
}
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, unsigned long * value)
{
	return any_unsigned_convert<wchar_t, unsigned long>(ptr, end, value);
}
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, __int64 * value)
{
	return any_int_convert<wchar_t,__int64>(ptr, end, value);
}
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, float * value)
{
	return any_float_convert(ptr, end, value);
}
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, double * value)
{
	return any_float_convert(ptr, end, value);
}
int simple_print(char * ptr, int value)
{
	return sprintf(ptr,"%d",value);
}
int simple_print(char * ptr, unsigned value)
{
	return sprintf(ptr,"%u",value);
}
int simple_print(char * ptr, long value)
{
	return sprintf(ptr,"%ld",value);
}
int simple_print(char * ptr, unsigned long value)
{
	return sprintf(ptr,"%lu",value);
}
int simple_print(char * ptr, __int64 value)
{
	// TODO - how to print such values?
	return sprintf(ptr,"%I64d",value);
}
int simple_print(char * ptr, float value)
{
	return sprintf(ptr,"%g",value);
}
int simple_print(char * ptr, double value)
{
	return sprintf(ptr,"%g",value);
}

#if (defined(_MSC_VER) && _MSC_VER < 1400)	//Visual < 8
int simple_print(wchar_t * ptr, int value)
{
	return swprintf(ptr,L"%d",value);
}
int simple_print(wchar_t * ptr, unsigned value)
{
	return swprintf(ptr,L"%u",value);
}
int simple_print(wchar_t * ptr, long value)
{
	return swprintf(ptr,L"%ld",value);
}
int simple_print(wchar_t * ptr, unsigned long value)
{
	return swprintf(ptr,L"%lu",value);
}
int simple_print(wchar_t * ptr, __int64 value)
{
	return swprintf(ptr,L"%I64d",value);
}
int simple_print(wchar_t * ptr, float value)
{
	return swprintf(ptr,L"%g",value);
}
int simple_print(wchar_t * ptr, double value)
{
	return swprintf(ptr,L"%g",value);
}
#else
int simple_print(wchar_t * ptr, int value)
{
	swprintf(ptr,56,L"%d",value);
	return wcslen( ptr );
}
int simple_print(wchar_t * ptr, unsigned value)
{
	swprintf(ptr,56,L"%u",value);
	return wcslen( ptr );
}
int simple_print(wchar_t * ptr, long value)
{
	swprintf(ptr,56,L"%ld",value);
	return wcslen( ptr );
}
int simple_print(wchar_t * ptr, unsigned long value)
{
	swprintf(ptr,56,L"%lu",value);
	return wcslen( ptr );
}
int simple_print(wchar_t * ptr, __int64 value)
{
	swprintf(ptr,56,L"%I64d",value);
	return wcslen( ptr );
}
int simple_print(wchar_t * ptr, float value)
{
	swprintf(ptr,56,L"%g",value);
	return wcslen( ptr );
}
int simple_print(wchar_t * ptr, double value)
{
	swprintf(ptr,56,L"%g",value);
	return wcslen( ptr );
}
#endif

bool simple_convert(const char * ptr, const char * end, wchar_t * buf)
{
	int count = end - ptr;
	if( count == 0 )
		return true;
#ifndef WIN_VERSION
	return mbstowcs( buf, ptr, count );
#else
	return MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, ptr, count, buf, count );
#endif
}
bool simple_convert(const wchar_t * ptr, const wchar_t * end, char * buf)
{
	int count = end - ptr;
	if( count == 0 )
		return true;
#ifndef WIN_VERSION
	return wcstombs( buf, ptr, count );
#else
	return WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, ptr, count, buf, count, 0, 0);
#endif
}

bool simple_convert(const char * ptr, const char * end, char * buf)
{
	int count = end - ptr;
	if( count == 0 )
		return true;
	return memcpy( buf, ptr, count * sizeof(char) );
}

bool simple_convert(const wchar_t * ptr, const wchar_t * end, wchar_t * buf)
{
	int count = end - ptr;
	if( count == 0 )
		return true;
	return memcpy( buf, ptr, count * sizeof(wchar_t) );
}

} // namespace converter
} // namespace liba

